package com.uinnova.product.eam.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.dao.CmdbSysSyncInfoDao;
import com.uinnova.product.eam.dao.CmdbSysSyncLogDao;
import com.uinnova.product.eam.init.cmdb.SyncCmdbSysSvc;
import com.uinnova.product.eam.model.es.CmdbSysSyncInfo;
import com.uinnova.product.eam.model.es.CmdbSysSyncLog;
import com.uinnova.product.eam.service.CmdbSysSyncService;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.cmdb.flowable.CmdbFlowResponse;
import com.uinnova.product.eam.vo.CmdbSysSyncInfoReq;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.permission.business.CurrentUserInfo;
import com.uino.dao.util.ESUtil;
import com.uino.service.permission.microservice.IUserSvc;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Log4j2
@Service
public class CmdbSysSyncServiceImpl implements CmdbSysSyncService {

    @Resource
    private CmdbSysSyncInfoDao cmdbSysSyncInfoDao;
    @Resource
    private CmdbSysSyncLogDao cmdbSysSyncLogDao;
    @Resource
    private SyncCmdbSysSvc syncCmdbSysSvc;
    @Resource
    private IUserSvc iUserSvc;
    @Resource
    private BmConfigSvc bmConfigSvc;
    @Resource
    private ICISwitchSvc iciSwitchSvc;

    @Override
    public Page<CmdbSysSyncInfo> page(CmdbSysSyncInfoReq req) {
        Assert.notNull(req, "入参不能为空");
        Assert.notNull(req.getPageNum(), "第几页不能为空");
        Assert.notNull(req.getPageSize(), "每页显示记录数不能为空");
        // 查询前先根据系统属性更新最新的系统数据
        updateData();
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if (!BinaryUtils.isEmpty(req.getName())) {
            // 系统名称/事项名称
            BoolQueryBuilder nameOrQuery = QueryBuilders.boolQuery();
            nameOrQuery.should(QueryBuilders.wildcardQuery("systemName.keyword", "*" + req.getName().trim() + "*"));
            nameOrQuery.should(QueryBuilders.wildcardQuery("itemName.keyword", "*" + req.getName().trim() + "*"));
            query.must(nameOrQuery);
        }
        if (!BinaryUtils.isEmpty(req.getPushStatus())) {
            query.must(QueryBuilders.termQuery("lastPushStatus.keyword", req.getPushStatus()));
        }
        if (!BinaryUtils.isEmpty(req.getPushTimeBegin()) || !BinaryUtils.isEmpty(req.getPushTimeEnd())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("lastPushTime");
            if (!BinaryUtils.isEmpty(req.getPushTimeBegin())) {
                rangeQuery.gte(req.getPushTimeBegin());
            }
            if (!BinaryUtils.isEmpty(req.getPushTimeEnd())) {
                rangeQuery.lte(req.getPushTimeEnd());
            }
            query.must(rangeQuery);
        }
        if (!BinaryUtils.isEmpty(req.getCreateTimeBegin()) || !BinaryUtils.isEmpty(req.getCreateTimeEnd())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("createTime");
            if (!BinaryUtils.isEmpty(req.getCreateTimeBegin())) {
                rangeQuery.gte(req.getCreateTimeBegin());
            }
            if (!BinaryUtils.isEmpty(req.getCreateTimeEnd())) {
                rangeQuery.lte(req.getCreateTimeEnd());
            }
            query.must(rangeQuery);
        }
        return cmdbSysSyncInfoDao.getSortListByQuery(req.getPageNum(), req.getPageSize(), query, "createTime", false);
    }

    /**
     * 根据系统属性更新推送页系统数据
     */
    private void updateData() {
        List<CmdbSysSyncInfo> cmdbSysSyncInfos = cmdbSysSyncInfoDao.getListByQueryScroll(QueryBuilders.boolQuery());
        if (BinaryUtils.isEmpty(cmdbSysSyncInfos)) {
            return;
        }
        List<String> ciCodes = cmdbSysSyncInfos.stream().map(CmdbSysSyncInfo::getCiCode).collect(Collectors.toList());
        /**
         * 从视图配置中获取配置信息
         */
        String config = bmConfigSvc.getConfigType("CMDB_SYS_SYNC_CONFIG");
        if (StrUtil.isEmpty(config)) {
            log.error("无法获取视图配置项 CMDB_SYS_SYNC_CONFIG");
            throw new BinaryException("无法获取视图配置项 CMDB_SYS_SYNC_CONFIG");
        }
        JSONObject jsonConfig = JSON.parseObject(config);
        //配置处理
        String systemClassCode = jsonConfig.getString("systemClassCode");
        if (StringUtils.isBlank(systemClassCode)) {
            log.error("无法获取视图配置项：systemClassCode");
            throw new BinaryException("无法获取视图配置项：systemClassCode");
        }
        JSONObject systemMap = jsonConfig.getJSONObject("systemMap");
        syncCmdbSysSvc.checkSysMap(systemMap);

        // 查询系统分类
        List<CcCiClassInfo> ciClassInfos = syncCmdbSysSvc.getClassInfos(Collections.singletonList(systemClassCode));
        if (CollectionUtils.isEmpty(ciClassInfos)) {
            log.error("系统分类未查到：{}", systemClassCode);
            throw new BinaryException("系统分类未查到");
        }
        Long systemClassId = ciClassInfos.get(0).getCiClass().getId();
        CCcCi cdt = new CCcCi();
        cdt.setClassId(systemClassId);
        cdt.setCiCodes(ciCodes.toArray(new String[0]));
        List<CcCiInfo> ciInfos = iciSwitchSvc.queryCiInfoList(1l, cdt, null, false, false, LibType.DESIGN);
        if (BinaryUtils.isEmpty(ciInfos)) {
            log.info("根据ciCodes未查到对应ci");
            return;
        }
        Map<String, List<CcCiInfo>> ciInfoMap = ciInfos.stream().collect(Collectors.groupingBy(each -> each.getCi().getCiCode()));

        for (CmdbSysSyncInfo info : cmdbSysSyncInfos) {
            List<CcCiInfo> ccCiInfos = ciInfoMap.get(info.getCiCode());
            if (!BinaryUtils.isEmpty(ccCiInfos)) {
                syncCmdbSysSvc.fillSyncInfo(systemMap, info, ccCiInfos.get(0).getAttrs());
            }
        }
        cmdbSysSyncInfoDao.saveOrUpdateBatch(cmdbSysSyncInfos);
    }

    @Override
    public List<CmdbSysSyncLog> logList(String ciCode) {
        Assert.notNull(ciCode, "ciCode不能为空");
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ciCode.keyword", ciCode));
        return cmdbSysSyncLogDao.getSortListByQuery(1, 3000, query, "pushTime", false).getData();
    }

    @Override
    public CmdbSysSyncLog push(CmdbSysSyncInfoReq req) {
        Assert.notNull(req, "入参不能为空");
        Assert.notNull(req.getCiCode(), "ciCode不能为空");
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ciCode.keyword", req.getCiCode()));
        Page<CmdbSysSyncInfo> page = cmdbSysSyncInfoDao.getListByQuery(1, 1, query);
        if (BinaryUtils.isEmpty(page.getData())) {
            throw new BinaryException("该条推送信息未查到，ciCode:" + req.getCiCode());
        }
        CmdbSysSyncInfo info = page.getData().get(0);

        /**
         * 从视图配置中获取配置信息
         */
        String config = bmConfigSvc.getConfigType("CMDB_SYS_SYNC_CONFIG");
        if (StrUtil.isEmpty(config)) {
            log.error("无法获取视图配置项 CMDB_SYS_SYNC_CONFIG");
            throw new BinaryException("无法获取视图配置项 CMDB_SYS_SYNC_CONFIG");
        }
        JSONObject jsonConfig = JSON.parseObject(config);
        //配置处理
        String systemClassCode = jsonConfig.getString("systemClassCode");
        if (StringUtils.isBlank(systemClassCode)) {
            log.error("无法获取视图配置项：systemClassCode");
            throw new BinaryException("无法获取视图配置项：systemClassCode");
        }
        JSONObject systemMap = jsonConfig.getJSONObject("systemMap");
        syncCmdbSysSvc.checkSysMap(systemMap);

        // 查询系统分类
        List<CcCiClassInfo> ciClassInfos = syncCmdbSysSvc.getClassInfos(Collections.singletonList(systemClassCode));
        if (CollectionUtils.isEmpty(ciClassInfos)) {
            log.error("系统分类未查到：{}", systemClassCode);
            throw new BinaryException("系统分类未查到");
        }
        Long systemClassId = ciClassInfos.get(0).getCiClass().getId();
        CCcCi cdt = new CCcCi();
        cdt.setClassId(systemClassId);
        cdt.setCiCode(info.getCiCode());
        List<CcCiInfo> ciInfos = iciSwitchSvc.queryCiInfoList(1l, cdt, null, false, false, LibType.DESIGN);
        if (BinaryUtils.isEmpty(ciInfos)) {
            throw new BinaryException("根据ciCode未查到对应ci:" + info.getCiCode());
        }

        syncCmdbSysSvc.fillSyncInfo(systemMap, info, ciInfos.get(0).getAttrs());

        //推送
        CmdbFlowResponse response = syncCmdbSysSvc.pushInfo(info);

        // 保存推送记录
        Long pushTime = ESUtil.getNumberDateTime();
        CmdbSysSyncLog cmdbSysSyncLog = new CmdbSysSyncLog();
        cmdbSysSyncLog.setCiCode(info.getCiCode());
        CurrentUserInfo currentUserInfo = iUserSvc.getCurrentUser();
        cmdbSysSyncLog.setUserName(currentUserInfo.getUserName());
        cmdbSysSyncLog.setUserCode(currentUserInfo.getLoginCode());
        cmdbSysSyncLog.setPushTime(pushTime);
        info.setLastPushTime(pushTime);
        if (response.getSuccess()) {
            cmdbSysSyncLog.setPushStatus("已推送");
            cmdbSysSyncLog.setPushResult("推送成功");
            info.setLastPushStatus("已推送");
            info.setLastPushResult("推送成功");
        } else {
            cmdbSysSyncLog.setPushStatus("推送失败");
            cmdbSysSyncLog.setPushResult(response.getError());
            info.setLastPushStatus("推送失败");
            info.setLastPushResult(response.getError());
        }
        cmdbSysSyncLogDao.saveOrUpdate(cmdbSysSyncLog);

        // 更新主推送信息的推送状态
        cmdbSysSyncInfoDao.saveOrUpdate(info);
        return cmdbSysSyncLog;
    }
}
